package com.mk.cloud.common.util;

import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.lang3.StringUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@SuppressWarnings("unused")
public class BeanUtils extends org.apache.commons.beanutils.BeanUtils {
    private static Map<Class, Field[]> classMapping = new ConcurrentHashMap<Class, Field[]>();
    private static Map<String, Method> setMethodMapping = new ConcurrentHashMap<String, Method>();
    private static Map<String, Method> getMethodMapping = new ConcurrentHashMap<String, Method>();
    private static Map<String, Field> fieldMapping = new ConcurrentHashMap<String, Field>();
    /**
     * 批量复制并返回新的集合
     *
     * @param list
     * @param classType
     * @return
     */
    public static <T> List copyBeans(List list, Class<T> classType) {
        if (list == null)
            return null;
        Iterator iterator = list.iterator();
        List<T> returnColl = new ArrayList();
        while (iterator.hasNext()) {
            Object object = iterator.next();
            try {
                Object o = classType.newInstance();
                copyProperties(o, object);
                returnColl.add((T) o);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return returnColl;
    }
    /**
     * 批量复制并返回新的属性
     *
     * @param src
     * @param classType
     * @param <T>
     * @return
     */
    public static <T> T copyBean(Object src, Class<T> classType) {
        try {
            Object o = classType.newInstance();
            copyProperties(o, src);
            return (T) o;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void stringSkipNull(Object obj) {
        try {
            PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
            PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(obj);
            for (PropertyDescriptor descriptor : descriptors) {
                String name = descriptor.getName();
                if (!StringUtils.equals(name, "class") && propertyUtilsBean.getPropertyDescriptor(obj, name).getPropertyType() == String.class) {
                    Object value = propertyUtilsBean.getNestedProperty(obj, name);
                    if (value != null && StringUtils.isBlank(value.toString())) {
                        propertyUtilsBean.setNestedProperty(obj, name, null);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void numberDefaultZero(Object obj) {
        try {
            PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
            PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(obj);
            for (PropertyDescriptor descriptor : descriptors) {
                String name = descriptor.getName();
                if (!StringUtils.equals(name, "class")) {
                    if (propertyUtilsBean.getPropertyDescriptor(obj, name).getPropertyType() == BigDecimal.class) {
                        Object value = propertyUtilsBean.getNestedProperty(obj, name);
                        if (value == null) {
                            propertyUtilsBean.setNestedProperty(obj, name, BigDecimal.ZERO);
                        }
                    } else if (propertyUtilsBean.getPropertyDescriptor(obj, name).getPropertyType() == Integer.class) {
                        Object value = propertyUtilsBean.getNestedProperty(obj, name);
                        if (value == null) {
                            propertyUtilsBean.setNestedProperty(obj, name, 0);
                        }
                    }
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 将对象中空字符串的属性 变为 null
     *
     * @param obj
     * @param skips 哪些字段设置为空字符串而不是null?
     */
    public static void stringSkipNull(Object obj, String... skips) {
        try {
            List<String> skipList = Arrays.asList(skips);
            String empty = "";
            PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
            PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(obj);
            for (PropertyDescriptor descriptor : descriptors) {
                String name = descriptor.getName();
                if (!StringUtils.equals(name, "class") && propertyUtilsBean.getPropertyDescriptor(obj, name).getPropertyType() == String.class) {
                    Object value = propertyUtilsBean.getNestedProperty(obj, name);
                    if (value != null && StringUtils.isBlank(value.toString())) {
                        if (skipList.indexOf(name) > -1) {
                            propertyUtilsBean.setNestedProperty(obj, name, empty);
                        } else {
                            propertyUtilsBean.setNestedProperty(obj, name, null);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取get方法名
     *
     * @param fieldName
     * @return
     */
    public static String getMethodName(String fieldName) {
        return "get" + firstToUpper(fieldName);
    }

    /**
     * 获取set方法名
     *
     * @param fieldName
     * @return
     */
    public static String setMethodName(String fieldName) {
        return "set" + firstToUpper(fieldName);
    }

    /**
     * 首字母转换大写
     *
     * @param str
     * @return
     */
    public static String firstToUpper(String str) {
        if (str == null)
            return null;
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

    /**
     * 首字母转换小写
     *
     * @param str
     * @return
     */
    public static String firstToLower(String str) {
        if (str == null)
            return null;
        return str.substring(0, 1).toLowerCase() + str.substring(1);
    }

    /**
    /**
     * 获取get方法
     *
     * @param fieldName
     * @param clz
     * @return
     * @throws SecurityException
     * @throws
     */
    public static Method getMethod(String fieldName, Class clz) {
        if (getMethodMapping.containsKey(fieldName + clz.getName())) {
            return getMethodMapping.get(fieldName + clz.getName());
        }
        Method method = null;
        String name = getMethodName(fieldName);
        for (; clz != Object.class; clz = clz.getSuperclass()) {
            try {
                method = clz.getMethod(name);
                getMethodMapping.put(fieldName + clz.getName(), method);
                return method;
            } catch (Exception e) {
            }
        }
        return null;
    }

    /**
     * 获取set方法
     *
     * @param field
     * @param clz
     * @return
     */
    public static Method setMethod(Field field, Class clz) {
        if (setMethodMapping.containsKey(field.getName() + clz.getName())) {
            return setMethodMapping.get(field.getName() + clz.getName());
        }
        Method method = null;
        String name = setMethodName(field.getName());
        for (; clz != Object.class; clz = clz.getSuperclass()) {
            try {
                method = clz.getMethod(name, field.getType());
                setMethodMapping.put(field.getName() + clz.getName(), method);
                return method;
            } catch (Exception e) {
            }
        }
        return null;
    }

    /**
     * 获取set方法
     *
     * @param fieldName
     * @param clz
     * @return
     */
    public static Method setMethod(String fieldName, Class clz) {
        if (setMethodMapping.containsKey(fieldName + clz.getName())) {
            return setMethodMapping.get(fieldName + clz.getName());
        }
        Method method = null;
        String name = setMethodName(fieldName);
        for (; clz != Object.class; clz = clz.getSuperclass()) {
            try {
                method = clz.getMethod(name, getField(fieldName, clz).getType());
                setMethodMapping.put(fieldName + clz.getName(), method);
                return method;
            } catch (Exception e) {
            }
        }
        return null;
    }

    /**
     * 获取字段
     *
     * @param fieldName
     * @param clz
     * @return
     */
    public static Field getField(String fieldName, Class clz) {
        if (fieldMapping.containsKey(fieldName + clz.getName())) {
            return fieldMapping.get(fieldName + clz.getName());
        }
        Field field = null;
        for (; clz != Object.class; clz = clz.getSuperclass()) {
            try {
                field = clz.getDeclaredField(fieldName);
                fieldMapping.put(fieldName + clz.getName(), field);
                return field;
            } catch (Exception e) {
            }
        }
        return null;
    }

}
